/**
 * Created by yuchen on 16/5/11.
 */

import java.awt.image.BufferedImage;
import java.util.ArrayList;

public class imageThreshold{

    public BufferedImage filter(BufferedImage src, BufferedImage dest) {
        int width = src.getWidth();
        int height = src.getHeight();

        if ( dest == null )
            dest = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
        // 图像灰度化
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        inPixels = src.getRGB(0, 0, width, height, null, 0, width);
        int index = 0;
        for(int row=0; row<height; row++) {
            int ta = 0, tr = 0, tg = 0, tb = 0;
            for(int col=0; col<width; col++) {
                index = row * width + col;
                ta = (inPixels[index] >> 24) & 0xff;
                tr = (inPixels[index] >> 16) & 0xff;
                tg = (inPixels[index] >> 8) & 0xff;
                tb = inPixels[index] & 0xff;
                int gray= (int)(0.299 *tr + 0.587*tg + 0.114*tb);
                inPixels[index]  = (ta << 24) | (gray << 16) | (gray << 8) | gray;
            }
        }
        // 获取直方图
        int[] histogram = new int[256];
        for(int row=0; row<height; row++) {
            int tr = 0;
            for(int col=0; col<width; col++) {
                index = row * width + col;
                tr = (inPixels[index] >> 16) & 0xff;
                histogram[tr]++;
            }
        }
        // 图像二值化 - OTSU 阈值化方法
        double total = width * height;
        double[] variances = new double[256];
        for(int i=0; i<variances.length; i++)
        {
            double bw = 0;
            double bmeans = 0;
            double bvariance = 0;
            double count = 0;
            for(int t=0; t<i; t++)
            {
                count += histogram[t];
                bmeans += histogram[t] * t;
            }
            bw = count / total;
            bmeans = (count == 0) ? 0 :(bmeans / count);
            for(int t=0; t<i; t++)
            {
                bvariance += (Math.pow((t-bmeans),2) * histogram[t]);
            }
            bvariance = (count == 0) ? 0 : (bvariance / count);
            double fw = 0;
            double fmeans = 0;
            double fvariance = 0;
            count = 0;
            for(int t=i; t<histogram.length; t++)
            {
                count += histogram[t];
                fmeans += histogram[t] * t;
            }
            fw = count / total;
            fmeans = (count == 0) ? 0 : (fmeans / count);
            for(int t=i; t<histogram.length; t++)
            {
                fvariance += (Math.pow((t-fmeans),2) * histogram[t]);
            }
            fvariance = (count == 0) ? 0 : (fvariance / count);
            variances[i] = bw * bvariance + fw * fvariance;
        }

        // find the minimum within class variance
        double min = variances[0];
        int threshold = 0;
        for(int m=1; m<variances.length; m++)
        {
            if(min > variances[m]){
                threshold = m;
                min = variances[m];
            }
        }
        // 二值化
        System.out.println("final threshold value : " + threshold);
        for(int row=0; row<height; row++) {
            for(int col=0; col<width; col++) {
                index = row * width + col;
                int gray = (inPixels[index] >> 8) & 0xff;
                if(gray > threshold)
                {
                    gray = 255;
                    outPixels[index]  = (0xff << 24) | (gray << 16) | (gray << 8) | gray;
                }
                else
                {
                    gray = 0;
                    outPixels[index]  = (0xff << 24) | (gray << 16) | (gray << 8) | gray;
                }

            }
        }
        for(int i = 0; i < height; i++)
        {
            for(int j = 0; j < width; j++)
            {
                dest.setRGB(j,i,outPixels[j+i*width]);
            }
        }
        return dest;
    }

    public ArrayList OTSUAlgorithm(BufferedImage src) {

        int width = src.getWidth();
        int height = src.getHeight();

        ArrayList returnResult = new ArrayList();
        double[] m_pFstdHistogram = new double[256];//表示灰度值的分布点概率
        double[] m_pFGrayAccu = new double[256]; //其中每一个值等于m_pFstdHistogram中从0到当前下标值的和
        double[] m_pFGrayAve = new double[256]; //其中每一值等于m_pFstdHistogram中从0到当前指定下标值*对应的下标之和
        double m_pAverage = 0; //值为m_pFstdHistogram【256】中每一点的分布概率*当前下标之和
        int[] m_pHistogram = new int[256]; //灰度直方图
        int i, j;
        double temp = 0, fMax = 0; //定义一个临时变量和一个最大类间方差的值
        int nThresh = 0; //最优阀值
        //初始化各项参数
        for (i = 0; i < 256; i++) {
            m_pFstdHistogram[i] = 0;
            m_pFGrayAccu[i] = 0;
            m_pFGrayAve[i] = 0;
            m_pHistogram[i] = 0;
        }
        //获取图像信息

        //获取图像的像素
        int pixels[] = src.getRGB(0, 0, width, height, null, 0, width);// 读进的图像的RGB值

        for (i = 0; i < pixels.length; i++) {
            //获取r的像素值，因为灰度图像，r=g=b，所以取第一个即可
            int r = pixels[i] & 0xff;
            m_pHistogram[r] ++;
        }

        //下面计算每一个灰度点在图像中出现的概率
        double size = width * height;
        for (i = 0; i < 256; i++) {
            m_pFstdHistogram[i] = m_pHistogram[i] / size;
        }
        //下面开始计算m_pFGrayAccu和m_pFGrayAve和m_pAverage的值
        for (i = 0; i < 256; i++) {
            for (j = 0; j <= i; j++) {
                //计算m_pFGaryAccu[256]
                m_pFGrayAccu[i] += m_pFstdHistogram[j];
                //计算m_pFGrayAve[256]
                m_pFGrayAve[i] += j * m_pFstdHistogram[j];
            }
            //计算平均值
            m_pAverage += i * m_pFstdHistogram[i];
        }
        //alert("m_pFstdHistogram:"+m_pFstdHistogram);
        //下面开始就算OSTU的值，从0-255个值中分别计算ostu并寻找出最大值作为分割阀值
        for (i = 0; i < 256; i++) {
            temp = (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) * (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) / (m_pFGrayAccu[i] * (1 - m_pFGrayAccu[i]));
            if (temp > fMax) {
                fMax = temp;
                nThresh = i;
            }
        }
        //mat为矩阵，存黑色为1，白色为0，为数字识别服务
        ArrayList mat = new ArrayList();
        ArrayList countX = new ArrayList();
        //黑白化之后进行数字黑背景区分，0，255两数，如果数字出现次数多就是背景，否则就是数字
        int blackLength = 0;


        int imageData[] = src.getRGB(0, 0, width, height, null, 0, width);// 读进的图像的RGB值
        //下面执行二值化过程
        for (i = 0; i < width; i++) {
            for (j = 0; j < height; j++) {
                int ids = (i + j * width);
                //取得像素的R分量的值
                int r = (imageData[ids] & 0xff0000) >> 16;
                //与阀值进行比较，如果小于阀值，那么将改点置为0，否则置为255
                //var gray = r > nThresh ? 255 : 0;
                int gray;
                if (r > nThresh) { //255白色
                    gray = 255;
                } else { //0黑色
                    gray = 0;
                    blackLength++;
                }
                int rgb =  (0xff << 24) | (gray << 16) | (gray << 8) | gray;
                imageData[ids] = rgb;
                if (i < 2 || j < 2 || i > (width - 2) || j > (height - 2)) {
                    imageData[ids] =  (0xff << 24) | (255 << 16) | (255 << 8) | 255;
                }
            }
        }

//        //BufferedImage dest = new BufferedImage(width,height,src.getType());
//        for(int x = 0; x < height; x++)
//        {
//            for(int y = 0; y < width; y++)
//            {
//                src.setRGB(y,x,imageData[y+x*width]);
//            }
//        }
        //显示二值化图像
        returnResult.add(imageData);
        returnResult.add(countX);
        returnResult.add(mat);
        return returnResult;
    }

    public ArrayList OTSUAlgorithm(int[] src , int width, int height) {


        ArrayList returnResult = new ArrayList();
        double[] m_pFstdHistogram = new double[256];//表示灰度值的分布点概率
        double[] m_pFGrayAccu = new double[256]; //其中每一个值等于m_pFstdHistogram中从0到当前下标值的和
        double[] m_pFGrayAve = new double[256]; //其中每一值等于m_pFstdHistogram中从0到当前指定下标值*对应的下标之和
        double m_pAverage = 0; //值为m_pFstdHistogram【256】中每一点的分布概率*当前下标之和
        int[] m_pHistogram = new int[256]; //灰度直方图
        int i, j;
        double temp = 0, fMax = 0; //定义一个临时变量和一个最大类间方差的值
        int nThresh = 0; //最优阀值
        //初始化各项参数
        for (i = 0; i < 256; i++) {
            m_pFstdHistogram[i] = 0;
            m_pFGrayAccu[i] = 0;
            m_pFGrayAve[i] = 0;
            m_pHistogram[i] = 0;
        }
        //获取图像信息

        //获取图像的像素
        int pixels[] = src;

        for (i = 0; i < pixels.length; i++) {
            //获取r的像素值，因为灰度图像，r=g=b，所以取第一个即可
            int r = pixels[i] & 0xff;
            m_pHistogram[r] ++;
        }

        //下面计算每一个灰度点在图像中出现的概率
        double size = width * height;
        for (i = 0; i < 256; i++) {
            m_pFstdHistogram[i] = m_pHistogram[i] / size;
        }
        //下面开始计算m_pFGrayAccu和m_pFGrayAve和m_pAverage的值
        for (i = 0; i < 256; i++) {
            for (j = 0; j <= i; j++) {
                //计算m_pFGaryAccu[256]
                m_pFGrayAccu[i] += m_pFstdHistogram[j];
                //计算m_pFGrayAve[256]
                m_pFGrayAve[i] += j * m_pFstdHistogram[j];
            }
            //计算平均值
            m_pAverage += i * m_pFstdHistogram[i];
        }
        //alert("m_pFstdHistogram:"+m_pFstdHistogram);
        //下面开始就算OSTU的值，从0-255个值中分别计算ostu并寻找出最大值作为分割阀值
        for (i = 0; i < 256; i++) {
            temp = (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) * (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) / (m_pFGrayAccu[i] * (1 - m_pFGrayAccu[i]));
            if (temp > fMax) {
                fMax = temp;
                nThresh = i;
            }
        }
        //mat为矩阵，存黑色为1，白色为0，为数字识别服务
        ArrayList mat = new ArrayList();
        ArrayList countX = new ArrayList();
        //黑白化之后进行数字黑背景区分，0，255两数，如果数字出现次数多就是背景，否则就是数字
        int blackLength = 0;


        int imageData[] = src;
        //下面执行二值化过程
        for (i = 0; i < width; i++) {
            for (j = 0; j < height; j++) {
                int ids = (i + j * width);
                //取得像素的R分量的值
                int r = (imageData[ids] & 0xff0000) >> 16;
                //与阀值进行比较，如果小于阀值，那么将改点置为0，否则置为255
                //var gray = r > nThresh ? 255 : 0;
                int gray;
                if (r > nThresh) { //255白色
                    gray = 255;
                } else { //0黑色
                    gray = 0;
                    blackLength++;
                }
                int rgb =  (0xff << 24) | (gray << 16) | (gray << 8) | gray;
                imageData[ids] = rgb;
                if (i < 2 || j < 2 || i > (width - 2) || j > (height - 2)) {
                    imageData[ids] =  (0xff << 24) | (255 << 16) | (255 << 8) | 255;
                }
            }
        }

//        //BufferedImage dest = new BufferedImage(width,height,src.getType());
//        for(int x = 0; x < height; x++)
//        {
//            for(int y = 0; y < width; y++)
//            {
//                src.setRGB(y,x,imageData[y+x*width]);
//            }
//        }
        //显示二值化图像
        returnResult.add(imageData);
        returnResult.add(countX);
        returnResult.add(mat);
        return returnResult;
    }


//    function makeHistogram(image_data)
//    {
//        console.log('histogram executed...');
//
//        var  data = image_data.data
//        var histogram = new Array(256);
//
//        // proses pembentukan histogram
//        for (var idx = 0; idx <  histogram.length; idx ++ )
//        {
//            histogram[idx] = 0;
//        }
//
//        for (var idx=0; idx < data.length; idx+=4) {
//            r = parseInt(data[idx]);
//            histogram[r] = histogram[r] + 1;
//        }
//        return histogram;
//    }
//
//    function equalization(image_data, histogram)
//    {
//        console.log('equalization executed...');
//        var d = image_data.data
//        var alpha = 255 / (image_data.width * image_data.height);
//        var temp_histogram = new Array(256);
//
//        // proses pembentukan histogram ekualisasi
//        for (var idx = 0; idx <  temp_histogram.length; idx ++ )
//        {
//            temp_histogram[idx] = 0;
//        }
//
//        // bug
//        temp_histogram[0] = Math.round(alpha * histogram[0]);
//
//        for (var i = 0; i < temp_histogram.length - 1; i++)
//        {
//            temp_histogram[i+1] = temp_histogram[i] + Math.round(alpha * histogram[i+1]);
//        }
//
//        console.log('processingg histogram...');
//
//        // proses penggantian warna
//        for (var i=0; i<d.length; i+=4) {
//
//            var r = d[i];
//
//            var v = temp_histogram[r];
//
//            d[i] = d[i+1] = d[i+2] = v;
//        }
//        return d;
//    }
//
//    //直方图均衡化函数
//    function processHistogramOperation (image_data)
//    {
//
//        console.log('processHistogramOperation is executed...');
//        var histogram = makeHistogram(image_data);
//
//        equalization(image_data, histogram);
//
//    }

}
